import AV from 'leancloud-storage'
import dayjs from 'dayjs'
import type { Object as LCObject } from 'leancloud-storage'
interface BaseObject {
  [key: string]: any
}
interface CallBackForQuery<T extends AV.Queriable> {
  (query: AV.Query<T>): AV.Query<T>
}

export default defineNuxtPlugin(() => {
  const config = useRuntimeConfig()
  AV.init({
    appId: config.public.LEAN_APPID,
    appKey: config.public.LEAN_APP_KEY,
    serverURL: config.public.LEAN_SERVER_URL
  })
  AV.setProduction(true)
  const lc = {
    AV: AV,
    /**
     * 批量创建
     * @param {array} objects
     */
    createAll: function (objects: LCObject[]) {
      return AV.Object.saveAll(objects)
    },
    /**
     * 批量删除
     * @param {array} objects
     */
    deleteAll: function (objects: LCObject[]) {
      return AV.Object.destroyAll(objects)
    },
    /**
     * 批量更新
     * @param {array} objects
     */
    updateAll: function (objects: LCObject[]) {
      return AV.Object.fetchAll(objects)
    },
    /**
     * 批量保存
     * @param {array} objects
     */
    saveAll: function (objects: LCObject[]) {
      return AV.Object.saveAll(objects)
    },
    /**
     * av新增对象
     * @param {string} classs 新增对象的类
     * @param {object} params 新增参数
     */
    create: function (classs: string, params: BaseObject) {
      return new (AV.Object.extend(classs))().set(params).save()
    },
    createObject(classs: string, id: string) {
      return AV.Object.createWithoutData(classs, id)
    },
    /**
     * av基础获取
     * @param {string} classs 搜索类名
     * @param {function} cbForQuery 设置查询条件的中介函数
     */
    read: function (classs: string, cbForQuery: CallBackForQuery<AV.Queriable>) {
      let query = new AV.Query(classs)
      // 如果需要额外设置条件，则通过传入这个函数处理
      if (cbForQuery) {
        // 如果是组合搜索，替换处理
        let temp_q = cbForQuery(query)
        if (temp_q) {
          query = temp_q
        }
      }
      return query.find()
    },
    query(classs: string, cbForQuery: CallBackForQuery<AV.Queriable>) {
      return this.read(classs, cbForQuery)
    },
    one(classs: string, cbForQuery: CallBackForQuery<AV.Queriable>) {
      return this.read(classs, cbForQuery).then((res) => res[0])
    },
    /**
     * av基础获取
     * @param {string} classs 搜索类名
     * @param {function} cbForQuery 设置查询条件的中介函数
     */
    readTotal: function (classs: string, cbForQuery: CallBackForQuery<AV.Queriable>) {
      let query = new AV.Query(classs)
      // 如果需要额外设置条件，则通过传入这个函数处理
      if (cbForQuery) {
        // 如果是组合搜索，替换处理
        let temp_q = cbForQuery(query)
        if (temp_q) {
          query = temp_q
        }
      }
      let result: AV.Queriable[]
      return query
        .find()
        .then((res) => {
          result = res
          return query.count()
        })
        .then((res) => {
          return {
            data: result,
            count: res
          }
        })
    },
    /**
     * av基础获取
     * @param {string} classs 搜索类名
     * @param {function} cbForQuery 设置查询条件的中介函数
     */
    readItem: function (classs: string, { id, key_list = [] } = {} as { id: string; key_list: string[] }) {
      let query = new AV.Query(classs)
      query.equalTo('objectId', id)
      for (let key of key_list) {
        query.include(key)
      }
      return query.first().then((res) => {
        if (!res) throw '数据错误'
        return res
      })
    },
    /**
     * av更新对象
     * @param {string} classs 更新对象的类
     * @param {string} id 更新对象的objectId
     * @param {object} params 更新内容
     */
    update: function (classs: string, id: string, params: BaseObject) {
      let obj = AV.Object.createWithoutData(classs, id)
      // 设置属性
      for (let key in params) {
        if (params.hasOwnProperty(key)) {
          let element = params[key]
          obj.set(key, element)
        }
      }
      return obj.save()
    },
    /**
     * av删除对象
     * @param {string} classs 删除对象的类
     * @param {string} id 删除对象的objectId
     */
    delete: function (classs: string, id: string) {
      let obj = AV.Object.createWithoutData(classs, id)
      return obj.destroy()
    },
    /**
     * 上传资源文件
     * @param {string} base64 文件base64
     */
    upload(base64: string, filename = new Date().getTime() / 1000 + '.png') {
      return new AV.File(filename, {
        base64
      }).save()
    },
    /**
     * 上传小程序资源文件
     * @param {string} path 文件路径
     */
    uploadMpFile(path: string) {
      return new AV.File(path, {
        blob: {
          uri: path
        }
      }).save()
    },
    uploadFile(file: File, file_name = new Date().getTime() / 1000 + '.png') {
      return new AV.File(file_name, file).save()
    },
    /**
     * 上传资源文件
     * @param {string} pat 文件路径
     */
    uploadBase64: function (base64: string, file_name: string) {
      if (!file_name) {
        file_name = dayjs.valueOf() + '.png'
      }
      return new AV.File(file_name, { base64: base64 }).save()
    },
    /**
     * av基础获取数量
     * @param {string} classs 搜索类名
     * @param {function} cbForQuery 设置查询条件的中介函数
     */
    count: function (classs: string, cbForQuery: CallBackForQuery<AV.Queriable>) {
      let query = new AV.Query(classs)
      // 如果需要额外设置条件，则通过传入这个函数处理
      if (cbForQuery) {
        // 如果是组合搜索，替换处理
        let temp_q = cbForQuery(query)
        if (temp_q) {
          query = temp_q
        }
      }
      return query.count()
    },
    /**
     * 登录
     */
    login: function (username: string, password: string) {
      return AV.User.logIn(username, password)
    },
    loginWithPhone: function (phone: string, password: string) {
      return AV.User.logInWithMobilePhone(phone, password)
    },
    loginWithWeChat: function () {
      return AV.User.loginWithMiniApp()
    },
    /**
     * 退出
     */
    logout: function () {
      return this.AV.User.logOut()
    },
    /**
     * 注册
     */
    regist: function (username: string, password: string) {
      // 创建实例
      let user = new AV.User()

      // 等同于 user.set('username', 'Tom')
      user.setUsername(username)
      user.setPassword(password)
      return user.signUp()
    },
    /**
     * session登录
     */
    become: function (session: string) {
      return AV.User.become(session)
    },
    /**
     * 获取当前用户
     */
    currentUser: function () {
      return AV.User.current()
    }
  }
  return {
    provide: {
      lc
    }
  }
})
